package components;
import java.math.BigInteger;
import java.util.Random;

/*
 * RSA key generator and message encipher/decipher.
 */

public class Rsa {	
	//Initialize variables used in private and public keys.
	private BigInteger n, d, e;

	//RSA Algorithm
	public Rsa(int bitLength, String mode){
		if (mode == "e=3"){
			Random rand = new Random();
			BigInteger p = new BigInteger(bitLength/2, 100, rand).abs();
			System.out.println("p = " + p.intValue());
			BigInteger q = new BigInteger(bitLength/2, 100, rand).abs();
			System.out.println("q = " + q.intValue());
			n = p.multiply(q);
			BigInteger totient = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
			e = new BigInteger("3");
			while(totient.gcd(e).intValue() > 1) e = e.add(new BigInteger("2"));
			d = e.modInverse(totient);			
		}

		else if(mode == "weiner"){
			Random rand = new Random();
			BigInteger p = new BigInteger(bitLength/2, 100, rand).abs();
			System.out.println("p = " + p.intValue());
			BigInteger q = new BigInteger(bitLength/2, 100, rand).abs();
			System.out.println("q = " + q.intValue());
			n = p.multiply(q);
			BigInteger totient = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
			e = new BigInteger("3");
			while(totient.gcd(e).intValue() > 1) e = e.add(new BigInteger("2"));
			d = e.modInverse(totient);			
			BigInteger tmp = e;
			e = d;
			d = tmp;
		}

		else {
			Random rand = new Random();
			BigInteger p = new BigInteger(bitLength, 100, rand).abs();
			System.out.println("p = " + p.intValue());
			BigInteger q = new BigInteger(bitLength, 100, rand).abs();
			System.out.println("q = " + q.intValue());
			n = p.multiply(q);
			BigInteger totient = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
			e = new BigInteger("65537");
			while(totient.gcd(e).intValue() > 1) e = e.add(new BigInteger("2"));
			d = e.modInverse(totient);			
		}
	}

	public Rsa(int bitLength){
		Random rand = new Random();
		BigInteger p = new BigInteger(bitLength/2, 100, rand).abs();
		System.out.println("p = " + p.intValue());
		BigInteger q = new BigInteger(bitLength/2, 100, rand).abs();
		System.out.println("q = " + q.intValue());
		n = p.multiply(q);
		BigInteger totient = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
		e = new BigInteger("3");
		while(totient.gcd(e).intValue() > 1) e = e.add(new BigInteger("2"));
		d = e.modInverse(totient);			
	}
	/**
	 * Get the public key pair as a BigInteger.
	 * @return An array consisting of the modulus n and the public exponent e.
	 */
	public BigInteger[] getBigPubKey(){
		return new BigInteger[] {n, e};
	}

	/**
	 * Get the private key pair as a BigInteger.
	 * @return An array consisting of the modulus n and the private exponent d
	 */
	public BigInteger[] getBigPrivKey(){
		return new BigInteger[] {n, d};
	}

	/**
	 * Get the public key pair as a int.
	 * @return An array consisting of the modulus n and the public exponent e.
	 */
	public int[] getPubKey(){
		return new int[] {n.intValue(), e.intValue()};
	}

	/**
	 * Get the public key as an RSAKey object
	 * @return
	 */
	public RSAKey getRSAPubKey(){
		return new RSAKey(n, e);
	}

	/**
	 * Get the private key pair as a int.
	 * @return An array consisting of the modulus n and the private exponent d
	 */
	public int[] getPrivKey(){
		return new int[] {n.intValue(), d.intValue()};
	}

	/**
	 * Get the private key as an RSAKey object
	 * @return
	 */
	public RSAKey getRSAPrivKey(){
		return new RSAKey(n, d);
	}

	/**
	 * Encipher a number.
	 * @param num - Number to encipher
	 * @return Ciphered number
	 */
	public BigInteger encipherNum(BigInteger num){
		return num.modPow(e, n);
	}

	/**
	 * Decipher a number.
	 * @param num - Ciphered number
	 * @return Deciphered number
	 */
	public BigInteger decipherNum(BigInteger num){
		return num.modPow(d, n);
	}


	public static void main(String[] args) {

	}


}
